//
//  ShareManager.swift
//  MMShareServiceDemo
//
//  Created by 吴传荣 on 2021/5/26.
//

import Foundation
import UIKit

typealias ShareResponse = ((_ result: Bool, _ errorMsg: String?) -> Void)?

public class ShareManager: NSObject {
    
    public static let manager = ShareManager()
    
    /// 回调信息
    private var shareResponse: ShareResponse = nil
    /// 小程序分享 id 登录小程序管理后台-设置-基本设置-帐号信息
    var WXMiniProgramUserName = ""
    
    public override init() {
        super.init()
    }
    
}

// MARK: 平台注册
extension ShareManager {
    
    // 微信注册
    public func wx_register(appid: String, universalLink: String, _ wxMiniProgramUserName: String = "", registerResult: ((Bool) -> Void)? = nil) {
        self.WXMiniProgramUserName = wxMiniProgramUserName
        let result = WXApi.registerApp(appid, universalLink: universalLink)
        if let registerResult = registerResult  {
            registerResult(result)
        }
    }
    
}

extension ShareManager {
    func shareAction(with messageObject: ShareMessageModel, response: ShareResponse = nil) {
        switch messageObject.shareSceneType {
        case .WXSceneSession, .WXSceneTimeline, .WXSceneFavorite:
            wxShare(with: messageObject, response: response)
        }
    }
}

// MARK: 微信分享 [ 文字、图片、音乐、视频、网页、小程序类型分享 ]
extension ShareManager {
    
    // https://developers.weixin.qq.com/doc/oplatform/Mobile_App/Share_and_Favorites/iOS.html
    
    private func wxShare(with messageObject: ShareMessageModel, response: ShareResponse = nil) {
        
        self.shareResponse = response
        let req = SendMessageToWXReq()
        req.bText = false
        
        switch messageObject.shareKind {
        case .text:
            req.bText = true
            req.text = messageObject.title
        case .image:
            guard let image = transformImage(with: messageObject.shareImage) else {
                // 获取图片信息失败
                let errorMsg = "获取图片信息失败"
                if let response = response { response(false, errorMsg) }
                return
            }
            let message = handleShareImage(with: messageObject, image)
            req.message = message
        case .web:
            let message = handleShareWeb(with: messageObject)
            req.message = message
        case .miniProgram:
            let message = handleShareMiniProgram(with: messageObject)
            req.message = message
        case .voice:
            let message = handleShareVoice(with: messageObject)
            req.message = message
        case .video:
            let message = handleShareVideo(with: messageObject)
            req.message = message
        }
        
        req.scene = Int32(messageObject.shareSceneType.rawValue)
        WXApi.send(req, completion: nil)
        
    }
    
    private func handleShareImage(with messageObject: ShareMessageModel, _ image: UIImage) -> WXMediaMessage {
        
        let message = setupWXMediaMessage(with: messageObject)
        
        // 图片缩略图不能超过64K
        let maxLengthThumb = 64 * 1024
        // 图片真实数据内容 大小不能超过25M
        let maxLengthImg = 25 * 1024 * 1024
        
        let (compressThumbImage, _) = compressImage(image, maxLengthThumb)
        message.setThumbImage(compressThumbImage)
        
        // 图片真实数据
        let imageObject = WXImageObject()
        let (_, realImageData) = compressImage(image, maxLengthImg)
        imageObject.imageData = realImageData ?? Data()
        
        message.mediaObject = imageObject
        return message
    }
    
    private func handleShareWeb(with messageObject: ShareMessageModel) -> WXMediaMessage {
        
        let message = setupWXMediaMessage(with: messageObject)
        let webpageObject = WXWebpageObject()
        webpageObject.webpageUrl = messageObject.webpageUrl
        message.mediaObject = webpageObject
        return message
    }
    
    private func handleShareMiniProgram(with messageObject: ShareMessageModel) -> WXMediaMessage {
        
        let message = setupWXMediaMessage(with: messageObject)
        let object = WXMiniProgramObject()
        object.webpageUrl = messageObject.webpageUrl
        object.path = messageObject.webpageUrl
        object.userName = self.WXMiniProgramUserName

        // 小程序新版本的预览图二进制数据 限制大小不超过128KB
        if let image = transformImage(with: messageObject.shareImage) {
            let maxLengthThumb = 128 * 1024
            let (_, thumbData) = compressImage(image, maxLengthThumb)
            object.hdImageData = thumbData
        }
        
        switch messageObject.miniProgramType {
        case .release:
            object.miniProgramType = .release
        case .preview:
            object.miniProgramType = .preview
        case .test:
            object.miniProgramType = .test
        }
        object.withShareTicket = false
        
        message.mediaObject = object
        return message
    }
    
    private func handleShareVoice(with messageObject: ShareMessageModel) -> WXMediaMessage {
        let message = setupWXMediaMessage(with: messageObject)
        let musicObject = WXMusicObject()
        musicObject.musicUrl = messageObject.shareVoiceModel.musicUrl
        musicObject.musicLowBandUrl = musicObject.musicUrl
        musicObject.musicDataUrl = messageObject.shareVoiceModel.musicDataUrl
        musicObject.musicLowBandDataUrl = musicObject.musicDataUrl
        message.mediaObject = musicObject
        return message
    }
    
    private func handleShareVideo(with messageObject: ShareMessageModel) -> WXMediaMessage {
        let message = setupWXMediaMessage(with: messageObject)
        let videoObject = WXVideoObject()
        videoObject.videoUrl = messageObject.shareVideoModel.videoUrl
        videoObject.videoLowBandUrl = messageObject.shareVideoModel.videoLowBandUrl
        message.mediaObject = videoObject
        return message
    }
    
    private func setupWXMediaMessage(with messageObject: ShareMessageModel) -> WXMediaMessage {
        let message = WXMediaMessage()
        message.title = messageObject.title
        message.description = messageObject.description
        // 缩略图
        if let image = transformImage(with: messageObject.shareImage) {
            let maxLengthThumb = 64 * 1024
            let (thumbImage, _) = compressImage(image, maxLengthThumb)
            message.setThumbImage(thumbImage)
        }
        return message
    }
    
}

// MARK: - 微信回调
extension ShareManager: WXApiDelegate {
    
    public func handleOpen(with url: URL) {
        // print("url : ", url.absoluteString)
        if !url.absoluteString.contains("wechat") { return }
        WXApi.handleOpen(url, delegate: self)
    }
    
    public func handleOpenUniversalLink(with userActivity: NSUserActivity) -> Bool {
        return WXApi.handleOpenUniversalLink(userActivity, delegate: self)
    }
    
    public func onResp(_ resp: BaseResp) {
        let success = resp.errCode == WXSuccess.rawValue
        if let response = shareResponse {
            response(success, resp.errStr)
        }
    }
}

// MARK: Util
extension ShareManager {
    
    /// 根据给定的数据返回图片
    private func transformImage(with shareContent: Any) -> UIImage? {
        
        var image: UIImage?
        
        if let tempImage = shareContent as? UIImage {
            image = tempImage
        }
        else if let imageUrl = shareContent as? String, let url = URL(string: imageUrl), let data = try? Data(contentsOf: url), let tempImage = UIImage(data: data) {
            image = tempImage
        }
        else if let data = shareContent as? Data, let tempImage = UIImage(data: data) {
            image = tempImage
        }
        
        return image
    }
    
    /// 压缩图片到指定尺寸
    private func compressImage(_ originalImage: UIImage, _ maxLength: NSInteger) -> (UIImage, Data?) {
        
        guard let data = originalImage.jpegData(compressionQuality: 1.0), data.count > 0 else {
            return (originalImage, nil)
        }
        
        var resutlImage = originalImage
        var cacheData = data
        var cacheDataLength = 0
        var normal = true
        
        while (cacheData.count > maxLength && cacheData.count != cacheDataLength && normal) {
            cacheDataLength = cacheData.count
            
            let ratio = CGFloat(maxLength) / CGFloat(cacheData.count)
            let size = CGSize(width: NSInteger(resutlImage.size.width * sqrt(ratio)), height: NSInteger(resutlImage.size.height * sqrt(ratio)))
            UIGraphicsBeginImageContext(size)
            resutlImage.draw(in: CGRect(x: 0, y: 0, width: size.width, height: size.height))
            let tempImage = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            
            if tempImage != nil, let lastData = tempImage!.jpegData(compressionQuality: 1.0) {
                resutlImage = tempImage!
                cacheData = lastData
            }
            else {
                normal = false
            }
        }
        
        return (resutlImage, cacheData)
    }
}
